<?php

class ProcrankParser {
    const LT_UNKNOWN = -1;
    const LT_TITLE = 0;
    const LT_PROCRANK = 1;
    const LT_SEPARATOR = 2;
    const LT_TOTAL = 3;
    const LT_RAM = 4;
    const LT_ZRAM = 5;

    private $mFile = null;
    private $mTemplate = null;

    public function ProcrankParser($file) {
        $this->mFile = $file;
        $this->mTemplate = file_get_contents(dirname(__FILE__) . "/template.html");
    }

    private function read() {
        $result = array();
        $contents = file($this->mFile);

        $delimiter = null;
        $index = 0;

        foreach ($contents as $line) {
            $line = trim($line);
            if (empty($line)) {
                continue;
            }
            if ($delimiter == null) {
                $delimiter = $line;
                $index = 0;
            } else if ($line == $delimiter) {
                $index++;
            }
            if (!isset($result[$index])) {
                $result[$index] = array();
                $result[$index]["procrank"] = array();
            }
            # echo "parsing line: $line \n";
            $lt = $this->lineType($line);
            if ($lt == self::LT_TITLE) {
                $result[$index]["title"] = $line;
            } else if ($lt == self::LT_PROCRANK) {
                $arr = $this->parseRankLine($line);
                if ($arr["cmd"] == "procrank") {
                    continue;
                }
                $result[$index]["procrank"][] = $arr;
            } else if ($lt == self::LT_SEPARATOR) {
            } else if ($lt == self::LT_TOTAL) {
                $result[$index]["used"] = $this->parseTotalLine($line);
            } else if ($lt == self::LT_RAM) {
                $result[$index]["info"] = $this->parseRamLine($line);
            } else if ($lt == self::LT_ZRAM) {
            } else {
                echo "unknown line: $line\n";
                // return false;
            }
        }
        return $result;
    }

    public function parseRankLine($line) {
        $arrs = explode(" ", $line);
        foreach ($arrs as $k => $v) {
            $v = trim($v);
            if (empty($v)) {
                unset($arrs[$k]);
            }
        }
        $arrs = array_values($arrs);
        $pid = $arrs[0];
        $pss = (int)$arrs[3];
        $cmdindex = count($arrs);
        $cmd = $arrs[$cmdindex - 1];
        return array("pid" => $pid, "pss" => $pss, "cmd" => $cmd);
    }

    public function parseTotalLine($line) {
        $total = (int)$line;
        return $total;
    }

    public function parseRamLine($line) {
        // $line = "RAM: 1526320K total, 235816K free, 27484K buffers, 685044K cached, 17200K shmem, 55288K slab";
        $total = 0;
        $free = 0;
        $buffers = 0;
        $cached = 0;
        $shmem = 0;
        $slab = 0;

        $arr1 = explode(", ", $line);
        foreach ($arr1 as $info) {
            $a = explode(" ", $info);
            if (strstr($info, " total") !== false) {
                $total = (int)$a[1];
            } else if (strstr($info, " free") !== false) {
                $free = (int)$a[0];
            } else if (strstr($info, " buffers") !== false) {
                $buffers = (int)$a[0];
            } else if (strstr($info, " cached") !== false) {
                $cached = (int)$a[0];
            } else if (strstr($info, " shmem") !== false) {
                $shmem = (int)$a[0];
            } else if (strstr($info, " slab") !== false) {
                $slab = (int)$a[0];
            } else {
            }
        }
        return array("total" => $total, "free" => $free, "buffers" => $buffers, "cached" => $cached, "shmem" => $shmem, "slab" => $slab);
    }

    private function lineType($line) {
        // if (strstr($line, "PID") !== false && strstr($line, "Pss") !== false && strstr($line, "cmdline") !== false) {
        //     return self::LT_TITLE;
        // }

        if (preg_match('/^PID\s+Vss\s+Rss\s+Pss\s+Uss\s+.*cmdline$/', $line) > 0) {
            return self::LT_TITLE;
        }

        if (preg_match('/^\d+\s+(\d+K\s+){4,8}\s+[A-Za-z0-9.\/:_<>\-@]+$/', $line) > 0) {
            return self::LT_PROCRANK;
        }

        if (preg_match('/^[ -]*$/', $line) > 0) {
            return self::LT_SEPARATOR;
        }

        if (preg_match('/^(\d+K\s+){2,6}TOTAL$/', $line) > 0) {
            return self::LT_TOTAL;
        }

        if (preg_match('/^RAM:\s+\d+K\s+total,\s+\d+K\s+free,\s+\d+K\s+buffers,\s+\d+K\s+cached,\s+\d+K\s+shmem,\s+\d+K\s+slab$/', $line) > 0) {
            return self::LT_RAM;
        }

        if (preg_match('/^ZRAM: .*$/', $line) > 0) {
            return self::LT_ZRAM;
        }

        return self::LT_UNKNOWN;
    }

    private function generateSummary($data) {
        $template_xaxis = array();
        $template_series = array(
            "used" => array("name" => "used", "type" => "line", "stack" => "total", "areaStyle" => array("normal" => array()), "data" => array()),
            "free" => array("name" => "free", "type" => "line", "stack" => "total", "areaStyle" => array("normal" => array()), "data" => array()),
            "buffers" => array("name" => "buffers", "type" => "line", "stack" => "total", "areaStyle" => array("normal" => array()), "data" => array()),
            "cached" => array("name" => "cached", "type" => "line", "stack" => "total", "areaStyle" => array("normal" => array()), "data" => array()),
            "shmem" => array("name" => "shmem", "type" => "line", "stack" => "total", "areaStyle" => array("normal" => array()), "data" => array()),
            "slab" => array("name" => "slab", "type" => "line", "stack" => "total", "areaStyle" => array("normal" => array()), "data" => array()),
        );

        foreach ($data as $k => $v) {
            $template_xaxis[] = "" . $k;
            $template_series["used"]["data"][] = $v["used"];
            $template_series["free"]["data"][] = $v["info"]["free"];
            $template_series["buffers"]["data"][] = $v["info"]["buffers"];
            $template_series["cached"]["data"][] = $v["info"]["cached"];
            $template_series["shmem"]["data"][] = $v["info"]["shmem"];
            $template_series["slab"]["data"][] = $v["info"]["slab"];
        }
        $template_xaxis = json_encode($template_xaxis);
        $template_series = array_values($template_series);
        $template_series = json_encode($template_series);

        $this->mTemplate = str_replace("TEMPLATE_XAXIS", $template_xaxis, $this->mTemplate);
        $this->mTemplate = str_replace("TEMPLATE_SERIES", $template_series, $this->mTemplate);
    }

    private function generateProc($data) {
        $procs = array();
        foreach ($data as $k => $v) {
            $procrank = $v["procrank"];
            foreach ($procrank as $rank) {
                $pid = $rank["pid"];
                $pss = $rank["pss"];
                $cmd = $rank["cmd"];
                $pname = $cmd . "(" . $pid . ")";
                if (!isset($procs[$pname])) {
                    $procs[$pname] = array();
                }
                $procs[$pname][$k] = $pss;
            }
        }
        $count = count($data);
        $template_procs = array();
        foreach ($procs as $pname => $ranks) {
            for ($i = 0; $i < $count; $i++) {
                if (!isset($ranks[$i])) {
                    $ranks[$i] = 0;
                }
            }
            ksort($ranks);
            $template_procs[] = array("name" => $pname, "ranks" => $ranks);
        }
        $template_procs = json_encode($template_procs);
        $this->mTemplate = str_replace("TEMPLATE_PROCS", $template_procs, $this->mTemplate);
    }

    public function parse() {
        $data = $this->read();
        if ($data === false) {
            return false;
        }

        $this->generateSummary($data);
        $this->generateProc($data);
        
        return $this->mTemplate;
    }

    public function save($file) {
        file_put_contents($file, $this->mTemplate);
    }
};


// $line = "2446   763416K   67340K   13596K   10992K  com.jamdeo.tv.mediacenter";
// $line = "                           ------   ------  ------ ";
// $line = "477721K  358540K  TOTAL";
// $line = "PID       Vss      Rss      Pss      Uss  cmdline";
// $line = " 1777   836792K  112772K   46480K   38588K  system_server";
// $line = "RAM: 1526320K total, 235816K free, 27484K buffers, 685044K cached, 17200K shmem, 55288K slab";
// $line = trim($line);
// $ret = preg_match('/^\d+\s+(\d+K\s+){4}\s+[A-Za-z0-9.\/:_]+$/', $line);
// $ret = preg_match('/^[ -]*$/', $line);
// $ret = preg_match('/^\d+K\s+\d+K\s+TOTAL$/', $line);
// $ret = preg_match('/^PID\s+Vss\s+Rss\s+Pss\s+Uss\s+cmdline$/', $line);
// $ret = preg_match('/^RAM:\s+\d+K\s+total,\s+\d+K\s+free,\s+\d+K\s+buffers,\s+\d+K\s+cached,\s+\d+K\s+shmem,\s+\d+K\s+slab$/', $line);
// print_r($ret);
// die("");

// if ($argc != 3) {
//     die("php parse.php procrank result.html\n");
// }
// $target = $argv[1];
// $result = $argv[2];
// $pp = new ProcrankParser($target);
// $pp->parse();
// $pp->save($result);



